//
//  AtLabel.m
//  HJiOSLib
//
//  Created by Ji Hu on 12-7-30.
//  Copyright (c) 2012年 爱辅导. All rights reserved.
//

#import "AtLabel.h"
#import <CoreText/CoreText.h>


@implementation AtLabelItem

@synthesize frame,range,string,frames;

-(id)init{
    self = [super init];
    
    if (self) {
        frames = [[NSMutableArray alloc] initWithCapacity:3];
    }
    
    return self;
}

-(void)dealloc{
    self.frames=nil;
    self.string=nil;
    [super dealloc];
}

@end

@interface AtLabel (Private)

-(void)buildFrame:(CFRange)range origin:(CGPoint)point;
-(void)buildAttributeText;
-(AtLabelItem*)caculateNearestItem:(CGPoint)point;

@end

@implementation AtLabel

@synthesize row;

-(void)dealloc{
    
    if (_labelitems) {
        [_labelitems release];_labelitems=nil;
    }
    
    if (attributedText) {
        [attributedText release]; attributedText = nil;
    }
    
    [super dealloc];
}

-(id)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    
    if (self) {
        self.userInteractionEnabled=YES;
    }
    
    return self;
}

-(void)setText:(NSString *)text{
    [super setText:text];
    
    if (_labelitems==nil) {
        _labelitems = [[NSMutableArray array] retain];
    }else {
        [_labelitems removeAllObjects];
    }
    
    [self buildAttributeText];
}

//#define RectCenter(rect) CGPointMake(rect.origin.x+rect.size.width/2,rect.origin.y

-(AtLabelItem*)caculateNearestItem:(CGPoint)point{
    
    int nearestItemIndex = 0;
    CGFloat distance = 0.0f;
    int i =0;
    
    for (AtLabelItem *item in _labelitems) {
        
        CGFloat avd =0.0f;
        
        for (NSValue *fr in item.frames) {
            
            CGRect r = fr.CGRectValue;
            CGPoint center = CGPointMake(r.origin.x+r.size.width/2, r.origin.y+r.size.height/2);
            CGFloat td = sqrtf(powf((center.x - point.x),2.0f) + powf((center.y-point.y), 2.0f));
            avd+=td;
        }
        
        if (item.frames.count>0) {
            avd = avd / item.frames.count;
        }
        
        NSLog(@"avd i=%d %f",i,avd);
        
        if (i==0) {
            distance = avd;
            nearestItemIndex = i;
        }else if(avd<distance){
            distance = avd;
            nearestItemIndex = i;
        }
        
        i++;
    }
    
    return [_labelitems objectAtIndex:nearestItemIndex];
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    
    UITouch *touch = [touches anyObject];
    
    CGPoint beginp = [touch locationInView:self];
    
    //    for (AtLabelItem *item in _labelitems) {
    //        CGRect itemframe = item.frame;
    //        if (CGRectContainsPoint(itemframe, beginp)) {
    //            clickRect=itemframe;
    //            [self setNeedsDisplayInRect:itemframe];
    //            break;
    //        }
    //    }
    
    AtLabelItem *item = [self caculateNearestItem:beginp];
    if (item) {
        clickItem = item;
        for (NSValue *fr in clickItem.frames) {
             [self setNeedsDisplayInRect:fr.CGRectValue];
        }
    }
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
    
//    UITouch *touch = [touches anyObject];
    
//    CGPoint endp = [touch locationInView:self];
    
    //    for (AtLabelItem *item in _labelitems) {
    //        CGRect itemframe = item.frame;
    //        if (CGRectContainsPoint(itemframe, endp)) {
    //            
    //            NSMutableDictionary *userinfo = [NSMutableDictionary dictionaryWithCapacity:3];
    //            [userinfo setObject:item.string forKey:@"string"];
    //            [userinfo setObject:[NSNumber numberWithInt:self.row] forKey:@"row"];
    //            AtLabelContentType type = [item.string hasPrefix:@"@"]?AtLabelContentTypeAt:AtLabelContentTypeUrl;
    //            [userinfo setObject:[NSNumber numberWithInt:type] forKey:AtLabelNotifacationUserInfoKeyContentType];
    //            [userinfo setObject:self forKey:@"atlabel"];
    //            [[NSNotificationCenter defaultCenter] postNotificationName:AtLabelURLNotification object:item.string userInfo:userinfo];
    //            break;
    //        }
    //    }
    
//    AtLabelItem *item = [self caculateNearestItem:endp];
    AtLabelItem *item = clickItem;
    
    if (item) {
        NSMutableDictionary *userinfo = [NSMutableDictionary dictionaryWithCapacity:3];
        [userinfo setObject:item.string forKey:@"string"];
        [userinfo setObject:[NSNumber numberWithInt:self.row] forKey:@"row"];
        AtLabelContentType type = [item.string hasPrefix:@"@"]?AtLabelContentTypeAt:AtLabelContentTypeUrl;
        [userinfo setObject:[NSNumber numberWithInt:type] forKey:AtLabelNotifacationUserInfoKeyContentType];
        [userinfo setObject:self forKey:@"atlabel"];
        [[NSNotificationCenter defaultCenter] postNotificationName:AtLabelURLNotification object:item.string userInfo:userinfo];
    }
    
//    clickRect = CGRectZero;
    clickItem = nil;
    [self setNeedsDisplay];
    //    NSLog(@"end x:%f y:%f",endp.x,endp.y);
}

-(void)buildFrame:(CFRange)range origin:(CGPoint)point{
    
    for (AtLabelItem *item in _labelitems) {
        NSRange itemrange = item.range;

        if (itemrange.location>=range.location||itemrange.length+itemrange.location<=range.length+range.location) {
            
            NSRange subrange = NSIntersectionRange(itemrange, NSMakeRange(range.location, range.length));
            
            if (subrange.length==0&&subrange.location==0) {
                continue;
            }
            
            CGRect frame = CGRectZero;
            frame.size.height = self.font.lineHeight;
            frame.origin.y = point.y;
            NSString *sub = [self.text substringWithRange:NSMakeRange(range.location, itemrange.location-range.location)];
//            NSString *sub = [self.text substringWithRange:subrange];
            frame.origin.x = [sub sizeWithFont:self.font].width;
//            frame.size.width = [iteNSString *subm.string sizeWithFont:self.font].width;
            frame.size.width = [item.string sizeWithFont:self.font].width;
            
//            item.frame=frame;
            NSLog(@"%p add rect %f %f",item,frame.origin.x,frame.origin.y);
            [item.frames addObject:[NSValue valueWithCGRect:frame]];
        }
    }
    
}

-(void)buildAttributeText{
    
    if (attributedText) {
        [attributedText release];
        attributedText = nil;
    }
    
    NSString *text = self.text;
    
    if (text==nil) {
        return;
    }
    
    attributedText = [[NSMutableAttributedString alloc] initWithString:text];
    
    //字体
    CTFontRef  font = CTFontCreateWithName((CFStringRef)self.font.fontName,self.font.pointSize,NULL);
    [attributedText addAttribute: (NSString*)(kCTFontAttributeName) value:(id)font range:NSMakeRange(0,text.length)];
    CFRelease(font);
    
    //换行模式...
    CTLineBreakMode lineBreakMode = kCTLineBreakByWordWrapping;//换行模式
    
    CTTextAlignment alignment = kCTLeftTextAlignment;//对齐方式
    
    float lineSpacing =0.1;//行间距
    
    CTParagraphStyleSetting paraStyles[3] = {
        
        {.spec = kCTParagraphStyleSpecifierLineBreakMode,.valueSize = sizeof(CTLineBreakMode), .value = (const void*)&lineBreakMode},
        
        {.spec = kCTParagraphStyleSpecifierAlignment,.valueSize = sizeof(CTTextAlignment), .value = (const void*)&alignment},
        
        {.spec = kCTParagraphStyleSpecifierLineSpacing,.valueSize = sizeof(CGFloat), .value = (const void*)&lineSpacing},
        
    };
    
    CTParagraphStyleRef style = CTParagraphStyleCreate(paraStyles,3);
    
    [attributedText addAttribute:(NSString*)(kCTParagraphStyleAttributeName) value:(id)style range:NSMakeRange(0,[text length])];
    
    CFRelease(style);
    
    //正则
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(@[a-zA-Z0-9_]+([\\s]|$))|(((?i:ftp|https?)://[-\\w]+(\\.\\w[-\\w]*)+|(?i:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\\.)+(?-i:com\\b|edu\\b|biz\\b|gov\\b|in(?:t|fo)\\b|mil\\b|net\\b|org\\b|[a-z][a-z]\\b))(:\\d+)?(/[\\.!?;<>()\\[\\]{}a-zA-Z0-9\\-=\\&\\#\\%\\,]*)*)" options:0 error:nil];
    NSArray *results = [regex matchesInString:text options:0 range:NSMakeRange(0, text.length)];
    for (NSTextCheckingResult *match in results) {
        //        NSLog(@"range %d %d %@",match.range.location,match.range.length,match.replacementString);
        [attributedText addAttribute:(NSString*)(kCTForegroundColorAttributeName) value:(id)[[UIColor blueColor]CGColor] range:match.range];
        [attributedText addAttribute:(NSString*)(kCTUnderlineStyleAttributeName) value:[NSNumber numberWithInt:kCTUnderlineStyleSingle] range:match.range];
        
        AtLabelItem *item = [[AtLabelItem alloc] init];
        item.range = match.range;
        item.string = [text substringWithRange:match.range];
        if ([item.string hasSuffix:@" "]) {
            item.string=[item.string substringWithRange:NSMakeRange(0, item.string.length-1)];
        }
        [_labelitems addObject:item];
        [item release];
    }
    
}

-(void)drawRect:(CGRect)rect{
    
    CGContextRef current = UIGraphicsGetCurrentContext();
    
    CGContextSetFillColorWithColor(current, [UIColor lightGrayColor].CGColor);
//    CGContextFillRect(current, clickRect);
    if (clickItem) {
        for (NSValue *fr in clickItem.frames) {
            CGContextFillRect(current, fr.CGRectValue);
        }
    }
    
    [super drawRect:rect];
    
}

-(void)drawTextInRect:(CGRect)rect{
    
    if (attributedText==nil) {
        return;
    }
    
    for (AtLabelItem *item in _labelitems) {
        [item.frames removeAllObjects];
    }
    
    //绘制文字..
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    CGContextSetTextMatrix(context,CGAffineTransformIdentity);//重置
    
    CGContextTranslateCTM(context,0,self.bounds.size.height); //y轴高度
    
    CGContextScaleCTM(context,1.0,-1.0);//y轴翻转
    
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedText);
    
    CGMutablePathRef path = CGPathCreateMutable();
    
    CGPathAddRect(path,NULL,self.bounds);
    
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter,CFRangeMake(0,attributedText.length),path,NULL);
    
    //get lines
    CFArrayRef lines = CTFrameGetLines(frame);
    int lineNumber = CFArrayGetCount(lines);
    CGPoint lineOrigins[lineNumber];
    CTFrameGetLineOrigins(frame,CFRangeMake(0,lineNumber), lineOrigins);
    for(int lineIndex = 0;lineIndex < lineNumber;lineIndex++){
        
        CGPoint lineOrigin = lineOrigins[lineIndex];
        
        lineOrigin.y=self.bounds.size.height-lineOrigin.y-self.font.pointSize;
        
        CTLineRef line = CFArrayGetValueAtIndex(lines,lineIndex);
        
        CFRange stringrange = CTLineGetStringRange(line);
        
        [self buildFrame:stringrange origin:lineOrigin];
        //         NSLog(@"cf range %zu %zu",stringrange.location,stringrange.length);
    }
    
    //actual draw.
    CTFrameDraw(frame,context);
    
    CFRelease(framesetter);
    
    CGPathRelease(path);
    
    CFRelease(frame);
    
    //    NSLog(@"%f %f %f",self.font.xHeight,self.font.lineHeight,self.font.pointSize);
}

@end
